package com.atlin.project.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.atlin.project.common.ErrorCode;
import com.atlin.project.config.AtLinConfig;
import com.atlin.project.contant.CommonConstant;
import com.atlin.project.exception.BusinessException;
import com.atlin.project.mapper.cds.ClientFileMapper;
import com.atlin.project.mapper.cds.FileMetadataMapper;
import com.atlin.project.model.domain.cds.ClientCode;
import com.atlin.project.model.domain.cds.ClientFile;
import com.atlin.project.model.domain.cds.FileMetadata;
import com.atlin.project.model.dto.clientFile.ClientFileQueryRequest;
import com.atlin.project.model.vo.cds.ClientFileVO;
import com.atlin.project.service.ClientCodeService;
import com.atlin.project.service.ClientFileService;
import com.atlin.project.service.FileMetadataService;
import com.atlin.project.utils.file.LocalFileUtil;
import com.atlin.project.utils.sql.SqlUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author atlin
 * @description clientFile
 * @createDate date
 */
@Slf4j
@Service
public class ClientFileServiceImpl extends ServiceImpl<ClientFileMapper, ClientFile>
        implements ClientFileService {

    private final static String FILE_PREFIX = "/cds";

    @Resource
    private ClientCodeService clientCodeService;

    @Resource
    private FileMetadataService fileMetadataService;

    @Resource
    private FileMetadataMapper fileMetadataMapper;

    @Override
    public void valid(ClientFile clientFile, boolean add) {

    }

    @Override
    public ClientFileVO getClientFileVO(ClientFile clientFile, HttpServletRequest request) {
        ClientFileVO clientFileVO = ClientFileVO.objToVo(clientFile);
        // todo other operation
        return clientFileVO;
    }

    /**
     * 获取查询包装类（用户根据哪些字段查询，根据前端传来的请求对象，得到 mybatis 框架支持的查询 QueryWrapper 类）
     *
     * @param clientFileQueryRequest
     * @return
     */
    @Override
    public QueryWrapper<ClientFile> getQueryWrapper(ClientFileQueryRequest clientFileQueryRequest) {
        QueryWrapper<ClientFile> queryWrapper = new QueryWrapper<>();
        if (clientFileQueryRequest == null) {
            return queryWrapper;
        }
        Long id = clientFileQueryRequest.getId();
//        String title = clientFileQueryRequest.getTitle();
//        String content = clientFileQueryRequest.getContent();
        String sortField = clientFileQueryRequest.getSortField();
        String sortOrder = clientFileQueryRequest.getSortOrder();

//        queryWrapper.like(StringUtils.isNotBlank(title), "title", title);
//        queryWrapper.like(StringUtils.isNotBlank(content), "content", content);
        queryWrapper.eq(ObjectUtils.isNotEmpty(id), "id", id);
        queryWrapper.eq("isDelete", false);
        queryWrapper.orderBy(SqlUtils.validSortField(sortField),
                sortOrder.equals(CommonConstant.SORT_ORDER_ASC), sortField);

        // todo other operation
        return queryWrapper;
    }

    @Override
    public Page<ClientFileVO> getClientFileVOPage(Page<ClientFile> clientFilePage, HttpServletRequest request) {
        List<ClientFile> clientFileList = clientFilePage.getRecords();
        Page<ClientFileVO> clientFileVOPage = new Page<>(clientFilePage.getCurrent(), clientFilePage.getSize(), clientFilePage.getTotal());
        if (CollectionUtils.isEmpty(clientFileList)) {
            return clientFileVOPage;
        }
        // todo other operation

        // 填充信息
        List<ClientFileVO> clientFileVOList = clientFileList.stream().map(clientFile -> {
            ClientFileVO clientFileVO = ClientFileVO.objToVo(clientFile);
            // todo other operation

            return clientFileVO;
        }).collect(Collectors.toList());
        clientFileVOPage.setRecords(clientFileVOList);
        return clientFileVOPage;
    }

    /**
     * 文件上传
     *
     * @param multipartFile 文件
     * @param newClientCode    客户端标识
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void uploadFile(MultipartFile multipartFile, ClientCode newClientCode) {

        ClientCode clientCode = clientCodeService.getOne(new LambdaQueryWrapper<ClientCode>()
                .eq(ClientCode::getCode, newClientCode.getCode()));
//         .eq(ClientCode::getFolderPath, clientCode.getFolderPath()))

        if (clientCode == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }

        String fileName = multipartFile.getOriginalFilename();
        String code = clientCode.getCode();
        String tempFilePath = String.format("%s/%s", FILE_PREFIX, fileName);
        File file = null;
        try {
            // 上传文件
            file = File.createTempFile(tempFilePath, null);
            multipartFile.transferTo(file);
            String fileParentPath = AtLinConfig.getUploadPath();
            // 文件最终存储路径
            String filePath = fileParentPath + FILE_PREFIX + File.separator + code;
            LocalFileUtil.save(file, fileName, filePath);

            String md5Hex = DigestUtil.md5Hex(file);
            FileMetadata oldFileMetadata = fileMetadataMapper.selectOne(new LambdaQueryWrapper<FileMetadata>()
                    .eq(FileMetadata::getFileHash, md5Hex));
            FileMetadata fileMetadata = new FileMetadata();
            if (oldFileMetadata != null) {
                fileMetadata.setId(oldFileMetadata.getId());
                log.info("oldFileMetadata {}", oldFileMetadata.getId());
            }

            fileMetadata.setFileName(fileName);
            fileMetadata.setFilePath(filePath);
            fileMetadata.setFileSize(multipartFile.getSize());
            fileMetadata.setFileHash(md5Hex);
            fileMetadata.setVersion(1);
            fileMetadata.setUserId(clientCode.getUserId());

            boolean save = fileMetadataService.saveOrUpdate(fileMetadata);

            String clientFilePath = newClientCode.getFolderPath();
            ClientFile clientFile = new ClientFile();

            ClientFile oldClientFile = this.getOne(new LambdaQueryWrapper<ClientFile>()
                    .eq(ClientFile::getFileMetadataId, fileMetadata.getId())
                    .eq(ClientFile::getClientCodeId, clientCode.getId())
                    .eq(ClientFile::getFilePath, clientFilePath));
            if (oldClientFile != null) {
                clientFile.setId(oldClientFile.getId());
                log.info("oldClientFile {}", oldClientFile.getId());
            }
            clientFile.setFileMetadataId(fileMetadata.getId());
            clientFile.setClientCodeId(clientCode.getId());
            clientFile.setFilePath(clientFilePath);

            save = this.saveOrUpdate(clientFile);

        } catch (Exception e) {
            log.error("file upload error, filepath = " + tempFilePath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "上传失败");
        } finally {
            if (file != null) {
                // 删除临时文件
                boolean delete = file.delete();
                if (!delete) {
                    log.error("file delete error, filepath = {}", tempFilePath);
                }
            }
        }
    }

    /**
     * 文件下载
     *
     * @param clientFile 客户端文件
     * @param response   响应
     */
    @Override
    public void downloadFile(ClientFile clientFile, HttpServletResponse response) {
        Long fileMetadataId = clientFile.getFileMetadataId();
        Long clientCodeId = clientFile.getClientCodeId();
        FileMetadata fileMetadata = fileMetadataService.getById(fileMetadataId);
        ClientCode clientCode = clientCodeService.getById(clientCodeId);

        if (fileMetadata == null || clientCode == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }

        String fileParentPath = AtLinConfig.getUploadPath();
        // 文件最终存储路径
//        String filePath = fileParentPath + FILE_PREFIX + File.separator + clientCode.getFolderPath();
        String filePath = fileMetadata.getFilePath();

        LocalFileUtil.download(fileMetadata.getFileName(), filePath, response);

    }
}




